/*******************************************************************************
 * Copyright (c) 2000, 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package edu.uts.reekie.designer.edit;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;

import org.eclipse.gef.AccessibleEditPart;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.requests.DropRequest;

import edu.uts.reekie.designer.edit.*;
import edu.uts.reekie.designer.figures.FigureFactory;
import edu.uts.reekie.designer.figures.NodeFigure;
import edu.uts.reekie.designer.model.ModelFactory;
import edu.uts.reekie.designer.model.ViewElement;
import edu.uts.reekie.designer.model.ViewNode;

/*
 * 
 * TODO: refactor this to be a base edit class for connectable diagram elements for all views
 * 
 */
public abstract class ViewNodeEditPart
	extends org.eclipse.gef.editparts.AbstractGraphicalEditPart
	implements NodeEditPart, PropertyChangeListener
{

	protected FigureFactory figureFactory;
	protected ModelFactory modelFactory;
	
	public ViewNodeEditPart(ModelFactory mf,FigureFactory ff ) {
		this.figureFactory = ff;
		this.modelFactory = mf;
		
	}
	
private AccessibleEditPart acc;

public void activate(){
	if (isActive())
		return;
	super.activate();
	getViewNode().addPropertyChangeListener(this);
}

protected void createEditPolicies(){
	installEditPolicy(EditPolicy.COMPONENT_ROLE, new ViewElementEditPolicy());
	// TODO: accept model and figure factories
	installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new ViewElementNodeEditPolicy(modelFactory,figureFactory));
}

abstract protected AccessibleEditPart createAccessible();

/**
 * Makes the EditPart insensible to changes in the model
 * by removing itself from the model's list of listeners.
 */
public void deactivate(){
	if (!isActive())
		return;
	super.deactivate();
	
	getViewNode().removePropertyChangeListener(this);
}

protected AccessibleEditPart getAccessibleEditPart() {
	if (acc == null)
		acc = createAccessible();
	return acc;
}

/**
 * Returns the model associated with this as a LogicSubPart.
 *
 * @return  The model of this as a LogicSubPart.
 */
protected ViewNode getViewNode(){
	return (ViewNode)getModel();
}

/* 
 * returns the model cast to the type parameter T
 * 
 */
public <T extends ViewNode> T getModelAs(){
	try {
		return (T) getModel();
	} catch (ClassCastException cce){
		throw new IllegalArgumentException("Model is not of the correct type. It is " + getModel().getClass().getName());
	}
	
}

/* 
 * returns the Figure cast to the type parameter T
 * 
 */
public <T extends Figure> T getFigureAs(){
	try {
		return (T) getFigure();
	} catch (ClassCastException cce){
		throw new IllegalArgumentException("Figure is not of the correct type. It is " + getFigure().getClass().getName());
	}
	
}

/**
 * Handles changes in properties of this. It is 
 * activated through the PropertyChangeListener.
 * It updates children, source and target connections,
 * and the visuals of this based on the property
 * changed.
 *
 * @param evt  Event which details the property change.
 */
public void propertyChange(PropertyChangeEvent evt){
	String prop = evt.getPropertyName();
	if (ViewNode.CHILDREN.equals(prop)) {
		if (evt.getOldValue() instanceof Integer)
			// new child
			addChild(createChild(evt.getNewValue()), ((Integer)evt
					.getOldValue()).intValue());
		else
			// remove child
			removeChild((EditPart)getViewer().getEditPartRegistry().get(
					evt.getOldValue()));
	}
	else if (ViewNode.PROPERTY_CONNECTORS_TARGET.equals(prop))
		refreshTargetConnections();
	else if (ViewNode.PROPERTY_CONNECTORS_SOURCE.equals(prop))
		refreshSourceConnections();
	else if (prop.equals(ViewNode.PROPERTY_SIZE) || prop.equals(ViewNode.PROPERTY_LOCATION))
		refreshVisuals();
}

/**
 * Updates the visual aspect of this. 
 */
protected void refreshVisuals() {
	Point loc = getViewNode().getLocation();
	Dimension size= getViewNode().getSize();
	Rectangle r = new Rectangle(loc ,size);

	((GraphicalEditPart) getParent()).setLayoutConstraint(
		this,
		getFigure(),
		r);
}

}
